package com.luisliuyi.demo.hook.ams;

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

public class HookUtils {
    private static final String TAG = "HookUtils";
    private Class<?> proxyActivity;
    private Context mContext;
    public HookUtils( Class<?> proxyActivity) {
        this.proxyActivity = proxyActivity;
    }

    public void hookAms(Context context) throws Exception {
        this.mContext = context;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            hookStartActivity1();
            hookActivityThreadMH2(context);
        } else  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//Oreo  8.0
            hookStartActivity2();
            hookActivityThreadMH2(context);
        } else {
            hookStartActivity3(context);
            hookActivityThreadMH3(context);
        }
    }

    public void hookStartActivity1(){
        try {
            Field defaultFiled = null;
            Object iActivityManagerObject = null;
            Field mInstance = null;
            Class<?> clazz = Class.forName("android.app.ActivityTaskManager");
            defaultFiled = clazz.getDeclaredField("IActivityTaskManagerSingleton");
            defaultFiled.setAccessible(true);
            Object defaultValue = defaultFiled.get(null);
            //反射SingleTon
            Class<?> SingletonClass = Class.forName("android.util.Singleton");
            Method method = SingletonClass.getDeclaredMethod("get");
            iActivityManagerObject = method.invoke(defaultValue);
            mInstance = SingletonClass.getDeclaredField("mInstance");
            mInstance.setAccessible(true);
            if (iActivityManagerObject != null) {
                //开始动态代理，用代理对象替换掉真实的ActivityManager，瞒天过海
                Class<?> IActivityManagerIntercept = Class.forName("android.app.IActivityTaskManager");
                AmsInvocationHandler handler = new AmsInvocationHandler(iActivityManagerObject);
                Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{IActivityManagerIntercept}, handler);
                //现在替换掉这个对象
                mInstance.set(defaultValue, proxy);
            }
        } catch (Exception e) {

        }
    }

    public void hookStartActivity2() {
        try {

            Class  ActivityManagerClz = Class.forName("android.app.ActivityManager");
            Field IActivityManagerSingletonFiled = ActivityManagerClz.getDeclaredField("IActivityManagerSingleton");
            IActivityManagerSingletonFiled.setAccessible(true);
            Object IActivityManagerSingletonObj = IActivityManagerSingletonFiled.get(null);
//        还原系统对象  IActivityManagerSingletonObj  顺腾摸瓜
            Class SingletonClz = Class.forName("android.util.Singleton");
//        反射代码  mInstance
            Field mInstanceField = SingletonClz.getDeclaredField("mInstance");
            mInstanceField.setAccessible(true);
            Object IActivityManagerObj=  mInstanceField.get(IActivityManagerSingletonObj);
            IActivityManagerObj.hashCode();
//        动态代理
            Class IActivityManagerClz = Class.forName("android.app.IActivityManager");


            Object proxyIActivityManager =Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class[]{IActivityManagerClz}, new AmsInvocationHandler(IActivityManagerObj));
            mInstanceField.setAccessible(true);
            mInstanceField.set(IActivityManagerSingletonObj,proxyIActivityManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void hookStartActivity3(Context context) {
        try {
            //根据class路径反射找到ActivityManagerNative类
            Class<?> ActivityManagerNativeCls = Class.forName("android.app.ActivityManagerNative");
            //找到ActivityManagerNative的成员变量：gDefault
            //注意：这里只是针对23版本，因为26版本的源码是getDefault，以后要写的时候要增加判断兼容
            Field gDefault = ActivityManagerNativeCls.getDeclaredField("gDefault");
            gDefault.setAccessible(true);
            //因为是静态变量，所以获取得到的是系统值(默认值是null)
            Object defaultValue = gDefault.get(null);

            //再反射找到Singleton对象，为什么要找这个需要看源码
            Class<?> SingletonClass = Class.forName("android.util.Singleton");
            //找到mInstance对象
            Field mInstance = SingletonClass.getDeclaredField("mInstance");
            mInstance.setAccessible(true);
            //还原IActivityManager对象
            Object iActivityManagerObject = mInstance.get(defaultValue);

            //通过动态代理将IActivityManager的startActivity方法拉到我们自己写的逻辑代码中来
            Class<?> IActivityManagerIntercept = Class.forName("android.app.IActivityManager");

            /**
             * 第一个参数：classLoader
             * 第二个参数：即将返回的对象，需要实现哪些接口
             * 第三个参数：是即将实现的接口，比如说此刻不会调用startActivity方法而是走InvocationHandler里面的invoke方法，
             *              同时invoke参数的method就是startActivity
             */
            Object oldIActivityManager = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class[]{IActivityManagerIntercept, View.OnClickListener.class},
                    new AmsInvocationHandler(iActivityManagerObject));

            /**
             * 将系统的IActivityManager替换成自己通过动态代理实现的对象
             */
            Log.d(TAG, "hookStartActivity: 将系统的IActivityManager替换成自己通过动态代理实现的对象");
            mInstance.set(defaultValue, oldIActivityManager);

        } catch (Exception e) {
            Log.e("wsj", "HookUtils hookStartActivity: " + "e" + e.getMessage());
            e.printStackTrace();
        }
    }

    public void hookActivityThreadMH2(Context context) {
        try {
            //反射找到ActivityThread类
            Class<?> forName = Class.forName("android.app.ActivityThread");
            //反射找到ActivityThead类中的静态成员变量：sCurrentActivityThread
            Field sCurrentActivityThread = forName.getDeclaredField("sCurrentActivityThread");
            sCurrentActivityThread.setAccessible(true);
            //静态成员变量是针对类本身的，所以可以通过get（null）方法获取ActivityThread类实例
            Object activityThreadObj = sCurrentActivityThread.get(null);

            //反射找到ActivityThread的mH对象
            Field handleField = forName.getDeclaredField("mH");
            handleField.setAccessible(true);
            //对象可以通过get方法获取本身的实体类，因为mH不是静态的，所以get方法必须传入ActivityThread类对象
            Handler mH = (Handler) handleField.get(activityThreadObj);
            //Hook点是Handler的handlerMessage，那么怎样拉到我们自己的代码里执行呢？
            //有两个方法，要么是动态代理，要么是设置接口
            //因为Handler这个类本身就提供了CallBack这个接口，我么可以复用它，然后执行我们自己的逻辑
            Field callbackField = Handler.class.getDeclaredField("mCallback");
            callbackField.setAccessible(true);
            //将重写后的callback接口，重写替换系统的callback，这样在系统执行Handler的callback时候，就是执行我们本地重写的callback
            callbackField.set(mH, new ActivityMH1(mH));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void hookActivityThreadMH3(Context context) {
        try {
            //反射找到ActivityThread类
            Class<?> forName = Class.forName("android.app.ActivityThread");
            //反射找到ActivityThead类中的静态成员变量：sCurrentActivityThread
            Field sCurrentActivityThread = forName.getDeclaredField("sCurrentActivityThread");
            sCurrentActivityThread.setAccessible(true);
            //静态成员变量是针对类本身的，所以可以通过get（null）方法获取ActivityThread类实例
            Object activityThreadObj = sCurrentActivityThread.get(null);

            //反射找到ActivityThread的mH对象
            Field handleField = forName.getDeclaredField("mH");
            handleField.setAccessible(true);
            //对象可以通过get方法获取本身的实体类，因为mH不是静态的，所以get方法必须传入ActivityThread类对象
            Handler mH = (Handler) handleField.get(activityThreadObj);
            //Hook点是Handler的handlerMessage，那么怎样拉到我们自己的代码里执行呢？
            //有两个方法，要么是动态代理，要么是设置接口
            //因为Handler这个类本身就提供了CallBack这个接口，我么可以复用它，然后执行我们自己的逻辑
            Field callbackField = Handler.class.getDeclaredField("mCallback");
            callbackField.setAccessible(true);
            //将重写后的callback接口，重写替换系统的callback，这样在系统执行Handler的callback时候，就是执行我们本地重写的callback
            callbackField.set(mH, new ActivityMH2(mH));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class ActivityMH1 implements android.os.Handler.Callback {

        private android.os.Handler mH;

        public ActivityMH1(android.os.Handler mH) {
            this.mH = mH;
        }

        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == 159) {
                try {
                    Class ClientTransactionClz = Class.forName("android.app.servertransaction.ClientTransaction");
                    if (!ClientTransactionClz.isInstance(msg.obj)) return false;

                    Class LaunchActivityItemClz = Class.forName("android.app.servertransaction.LaunchActivityItem");

                    Field mActivityCallbacksField = ClientTransactionClz.getDeclaredField("mActivityCallbacks");//ClientTransaction的成员
//设值可访问
                    mActivityCallbacksField.setAccessible(true);
                    Object mActivityCallbacksObj = mActivityCallbacksField.get(msg.obj);
                    List list = (List) mActivityCallbacksObj;
                    if (list.size() == 0) return false;
                    Object LaunchActivityItemObj = list.get(0);
                    if (!LaunchActivityItemClz.isInstance(LaunchActivityItemObj)) return false;

//                    startActivity  一定是
                    Field mIntentField = LaunchActivityItemClz.getDeclaredField("mIntent");
                    mIntentField.setAccessible(true);
                    Intent mIntent = (Intent) mIntentField.get(LaunchActivityItemObj);
                    Intent realIntent = mIntent.getParcelableExtra("oldIntent");
                    if (realIntent != null) {
//                        SecondActivity
//                        登录判断
                        SharedPreferences share = mContext.getSharedPreferences("ck",
                                Context.MODE_PRIVATE);
                        if (share.getBoolean("login", false)) {
                            mIntent.setComponent(realIntent.getComponent());
                        } else {
                            ComponentName componentName = new ComponentName(mContext, LoginActivity.class);
                            mIntent.putExtra("extraIntent", realIntent.getComponent()
                                    .getClassName());
                            mIntent.setComponent(componentName);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    }

    class ActivityMH2 implements android.os.Handler.Callback {

        private android.os.Handler mH;

        public ActivityMH2(android.os.Handler mH) {
            this.mH = mH;
        }

        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == 100) {
                //代表是系统要执行LaunchActivity这个方法了，我们就在这里给它进行还原
                reserLaunchActivity(msg);
            }
            mH.handleMessage(msg);
            return true;
        }

        private void reserLaunchActivity(Message msg) {
            //还原
            Object obj = msg.obj;
            try {
                Field intentField = obj.getClass().getDeclaredField("intent");
                intentField.setAccessible(true);
                //这个是ProxyActivity
                Intent realIntent = (Intent) intentField.get(obj);

                //这个是SecondActivity
                Intent oldIntent = realIntent.getParcelableExtra("oldIntent");

                if (oldIntent != null) {
                    //这里做集中式登录
                    SharedPreferences sharedPreferences = mContext.getSharedPreferences("ck", Context.MODE_PRIVATE);
                    if (sharedPreferences.getBoolean("login", false)) {
                        //如果是已经登录过了，就把原有的意图放到realyIntent
                        realIntent.setComponent(oldIntent.getComponent());
                    } else {
                        //没有登录过，统一调整到LoginActivity进行登录
                        ComponentName componentName = new ComponentName(mContext, LoginActivity.class);
                        realIntent.putExtra("extraIntent", oldIntent.getComponent().getClassName());
                        realIntent.setComponent(componentName);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class AmsInvocationHandler implements InvocationHandler {
        private Object iActivityManagerObject;
        public AmsInvocationHandler(Object iActivityManagerObject) {
            this.iActivityManagerObject = iActivityManagerObject;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.i("luis","method.getName " + method.getName());
            if ("startActivity".contains(method.getName())) {
                Intent intent = null;
                int index = 0;
                for (int i = 0; i < args.length; i++) {
                    Object arg = args[i];
                    if (arg instanceof Intent) {
                        intent = (Intent) args[i]; // 原意图，过不了安检
                        index = i;
                        break;
                    }
                }
                Intent proxyIntent = new Intent();
                ComponentName componentName = new ComponentName(mContext, proxyActivity);
                proxyIntent.setComponent(componentName);
                proxyIntent.putExtra("oldIntent", intent);
                args[index] = proxyIntent;
            }
            return method.invoke(iActivityManagerObject, args);
        }
    }
}
